<template>
	<div
		class="group"
		:class="{
			'opacity-40': !updating,
			'opacity-70': updating,
		}"
		@click.stop>
		<div
			class="padding-handler pointer-events-none absolute flex w-full bg-purple-400"
			:style="{
				height: topPaddingHandlerHeight + 'px',
			}"
			ref="topPaddingHandler">
			<div
				class="pointer-events-auto absolute left-[50%] rounded-full border-2 border-purple-500 bg-purple-400 hover:scale-125"
				v-show="canvasProps.scale > 0.5"
				:style="{
					borderWidth: handleBorderWidth,
					bottom: topHandle.bottom,
					left: topHandle.left,
					height: topHandle.height + 'px',
					width: topHandle.width + 'px',
				}"
				:class="{
					'cursor-ns-resize': !disableHandlers,
					hidden: updating,
				}"
				@mousedown.stop="handlePadding($event, Position.Top)" />
			<div class="m-auto text-sm text-purple-900" v-show="updating">
				{{ blockStyles.paddingTop }}
			</div>
		</div>
		<div
			class="padding-handler pointer-events-none absolute bottom-0 flex w-full bg-purple-400"
			:style="{
				height: bottomPaddingHandlerHeight + 'px',
			}"
			ref="bottomPaddingHandler">
			<div
				class="pointer-events-auto absolute left-[50%] rounded-full border-2 border-purple-500 bg-purple-400 hover:scale-125"
				v-show="canvasProps.scale > 0.5"
				:style="{
					borderWidth: handleBorderWidth,
					top: bottomHandle.top,
					left: bottomHandle.left,
					height: bottomHandle.height + 'px',
					width: bottomHandle.width + 'px',
				}"
				:class="{
					'cursor-ns-resize': !disableHandlers,
					hidden: updating,
				}"
				@mousedown.stop="handlePadding($event, Position.Bottom)" />
			<div class="m-auto text-sm text-purple-900" v-show="updating">
				{{ blockStyles.paddingBottom }}
			</div>
		</div>
		<div
			class="padding-handler pointer-events-none absolute left-0 flex h-full bg-purple-400"
			:style="{
				width: leftPaddingHandlerWidth + 'px',
			}"
			ref="leftPaddingHandler">
			<div
				class="pointer-events-auto absolute top-[50%] rounded-full border-2 border-purple-500 bg-purple-400 hover:scale-125"
				v-show="canvasProps.scale > 0.5"
				:style="{
					borderWidth: handleBorderWidth,
					right: leftHandle.right,
					top: leftHandle.top,
					height: leftHandle.height + 'px',
					width: leftHandle.width + 'px',
				}"
				:class="{
					'cursor-ew-resize': !disableHandlers,
					hidden: updating,
				}"
				@mousedown.stop="handlePadding($event, Position.Left)" />
			<div class="m-auto text-sm text-purple-900" v-show="updating">
				{{ blockStyles.paddingLeft }}
			</div>
		</div>
		<div
			class="padding-handler pointer-events-none absolute right-0 flex h-full bg-purple-400"
			:style="{
				width: rightPaddingHandlerWidth + 'px',
			}"
			ref="rightPaddingHandler">
			<div
				class="pointer-events-auto absolute top-[50%] rounded-full border-2 border-purple-500 bg-purple-400 hover:scale-125"
				v-show="canvasProps.scale > 0.5"
				:style="{
					borderWidth: handleBorderWidth,
					left: rightHandle.left,
					top: rightHandle.top,
					height: rightHandle.height + 'px',
					width: rightHandle.width + 'px',
				}"
				:class="{
					'cursor-ew-resize': !disableHandlers,
					hidden: updating,
				}"
				@mousedown.stop="handlePadding($event, Position.Right)" />
			<div class="m-auto text-sm text-purple-900" v-show="updating">
				{{ blockStyles.paddingRight }}
			</div>
		</div>
	</div>
</template>
<script setup lang="ts">
import { clamp } from "@vueuse/core";
import { computed, inject, ref, watchEffect } from "vue";
import Block from "../utils/block";
import { getNumberFromPx } from "../utils/helpers";

import { toast } from "vue-sonner";
const canvasProps = inject("canvasProps") as CanvasProps;

const props = defineProps({
	targetBlock: {
		type: Block,
		required: true,
	},
	disableHandlers: {
		type: Boolean,
		default: false,
	},
	onUpdate: {
		type: Function,
		default: null,
	},
	breakpoint: {
		type: String,
		default: "desktop",
	},
	target: {
		type: [HTMLElement, SVGElement],
		required: true,
	},
});

const updating = ref(false);
const emit = defineEmits(["update"]);

watchEffect(() => {
	emit("update", updating.value);
});

const blockStyles = computed(() => {
	let styleObj = props.targetBlock.baseStyles;
	if (props.breakpoint === "mobile") {
		styleObj = { ...styleObj, ...props.targetBlock.mobileStyles };
	} else if (props.breakpoint === "tablet") {
		styleObj = { ...styleObj, ...props.targetBlock.tabletStyles };
	}
	return styleObj;
});

const topPaddingHandlerHeight = computed(() => {
	return getPadding("Top");
});

const bottomPaddingHandlerHeight = computed(() => {
	return getPadding("Bottom");
});

const leftPaddingHandlerWidth = computed(() => {
	return getPadding("Left");
});

const rightPaddingHandlerWidth = computed(() => {
	return getPadding("Right");
});

const getPadding = (side: "Top" | "Left" | "Right" | "Bottom") => {
	blockStyles.value.paddingRight;
	blockStyles.value.paddingTop;
	blockStyles.value.paddingBottom;
	blockStyles.value.paddingLeft;
	blockStyles.value.padding;
	return getNumberFromPx(getComputedStyle(props.target)[`padding${side}`]) * canvasProps.scale;
};

const handleBorderWidth = computed(() => {
	return `${clamp(1 * canvasProps.scale, 1, 2)}px`;
});

const topHandle = computed(() => {
	const width = clamp(16 * canvasProps.scale, 8, 32);
	const height = clamp(4 * canvasProps.scale, 2, 8);
	return {
		width: width,
		height: height,
		bottom: `clamp(-20px, calc(-6px * ${canvasProps.scale}), -8px)`,
		left: `calc(50% - ${width / 2}px)`,
	};
});

const bottomHandle = computed(() => {
	const width = clamp(16 * canvasProps.scale, 8, 32);
	const height = clamp(4 * canvasProps.scale, 2, 8);
	return {
		width: width,
		height: height,
		top: `clamp(-20px, calc(-6px * ${canvasProps.scale}), -8px)`,
		left: `calc(50% - ${width / 2}px)`,
	};
});

const leftHandle = computed(() => {
	const width = clamp(4 * canvasProps.scale, 2, 8);
	const height = clamp(16 * canvasProps.scale, 8, 32);
	return {
		width: width,
		height: height,
		right: `clamp(-20px, calc(-6px * ${canvasProps.scale}), -8px)`,
		top: `calc(50% - ${height / 2}px)`,
	};
});

const rightHandle = computed(() => {
	const width = clamp(4 * canvasProps.scale, 2, 8);
	const height = clamp(16 * canvasProps.scale, 8, 32);
	return {
		width: width,
		height: height,
		left: `clamp(-20px, calc(-6px * ${canvasProps.scale}), -8px)`,
		top: `calc(50% - ${height / 2}px)`,
	};
});

enum Position {
	Top = "top",
	Right = "right",
	Bottom = "bottom",
	Left = "left",
}

const messageShown = ref(false);

const handlePadding = (ev: MouseEvent, position: Position) => {
	if (props.disableHandlers) return;
	// if (!messageShown.value && !(ev.shiftKey || ev.altKey)) {
	// 	showToast();
	// 	messageShown.value = true;
	// }
	updating.value = true;
	const startY = ev.clientY;
	const startX = ev.clientX;
	const target = ev.target as HTMLElement;

	const startTop = getNumberFromPx(blockStyles.value.paddingTop) || 5;
	const startBottom = getNumberFromPx(blockStyles.value.paddingBottom) || 5;
	const startLeft = getNumberFromPx(blockStyles.value.paddingLeft) || 5;
	const startRight = getNumberFromPx(blockStyles.value.paddingRight) || 5;

	// to disable cursor jitter
	const docCursor = document.body.style.cursor;
	document.body.style.cursor = window.getComputedStyle(target).cursor;

	const mousemove = (mouseMoveEvent: MouseEvent) => {
		let movement = 0;
		let affectingAxis = null;
		props.onUpdate && props.onUpdate();
		if (position === Position.Top) {
			movement = Math.max(startTop + mouseMoveEvent.clientY - startY, 0);
			props.targetBlock.setStyle("paddingTop", movement + "px");
			affectingAxis = "y";
		} else if (position === Position.Bottom) {
			movement = Math.max(startBottom + startY - mouseMoveEvent.clientY, 0);
			props.targetBlock.setStyle("paddingBottom", movement + "px");
			affectingAxis = "y";
		} else if (position === Position.Left) {
			movement = Math.max(startLeft + mouseMoveEvent.clientX - startX, 0);
			props.targetBlock.setStyle("paddingLeft", movement + "px");
			affectingAxis = "x";
		} else if (position === Position.Right) {
			movement = Math.max(startRight + startX - mouseMoveEvent.clientX, 0);
			props.targetBlock.setStyle("paddingRight", movement + "px");
			affectingAxis = "x";
		}

		if (mouseMoveEvent.altKey) {
			if (affectingAxis === "y") {
				props.targetBlock.setStyle("paddingTop", movement + "px");
				props.targetBlock.setStyle("paddingBottom", movement + "px");
			} else if (affectingAxis === "x") {
				props.targetBlock.setStyle("paddingLeft", movement + "px");
				props.targetBlock.setStyle("paddingRight", movement + "px");
			}
		} else if (mouseMoveEvent.shiftKey) {
			props.targetBlock.setStyle("paddingTop", movement + "px");
			props.targetBlock.setStyle("paddingBottom", movement + "px");
			props.targetBlock.setStyle("paddingLeft", movement + "px");
			props.targetBlock.setStyle("paddingRight", movement + "px");
		}

		mouseMoveEvent.preventDefault();
		mouseMoveEvent.stopPropagation();
	};
	document.addEventListener("mousemove", mousemove);
	document.addEventListener(
		"mouseup",
		(mouseUpEvent) => {
			document.body.style.cursor = docCursor;
			document.removeEventListener("mousemove", mousemove);
			updating.value = false;
			mouseUpEvent.preventDefault();
		},
		{ once: true }
	);
};

let showToast = () =>
	toast('Press "shift" key to apply padding to all sides and "alt" key to apply padding on either sides.');
</script>
